#include <time.h>
#include "csnode.h"
#include "utils.h"
#include "coord.h"
#include "emitter.h"
#include "laser.h"

#ifdef __cplusplus
extern "C" {
#endif

CS_BUF_DECLAR(CSNODE_BUF_SIZE, csnode_t)
/*********************| extern data |*********************/
CSB_DLL float _vworld_w = 480.0f;
CSB_DLL float _vworld_h = 800.0f;

#define next_emit_time(_node_) \
	_node_->nextEm = _node_->nframe + _node_->pobj->freq + RAND_VAR_INT(_node_->pobjdata->freqVar)

/*********************| extern functions |*********************/

CSB_DLL void csnode_buf_init() { CS_BUF_INIT(csnode_t); }

CSB_DLL void csnode_buf_end(bool force) { CS_BUF_END(csnode_t, force); }

CSB_DLL csnode_t* csnode_buf_rent(csobjdata_t* pobjdata, const node_cb_t* pcb, const int ctl)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_RET(pobjdata, CSBERR_PARAM, NULL);
	CS_BUF_RENT(csnode_t, ret);
	memset(ret, 0, sizeof(csnode_t));
	ret->pobjdata = pobjdata;
	ret->nframe = 0;
	list_init(&ret->bulist);
	// 计算得到第一次发射的时间
	srand(time(0));
	if (pcb) {
		memcpy(&ret->cbs, pcb, sizeof(node_cb_t));
	} else {
		memset(&ret->cbs, 0, sizeof(node_cb_t));
	}
	ret->ctlflag = ctl;
	if (ret->cbs.on_am) {
		ret->cbs.on_am(&ret->cbs.autoPos, ret->cbs.udata);
	} else {
		ret->cbs.autoPos.x = ret->cbs.autoPos.y = BODY_SELF;
	}
	ret->pobj = csobjdata_make_obj(pobjdata);
	next_emit_time(ret);
	return ret;
}

CSB_DLL void csnode_zero_bulist(csnode_t* pnode)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_VRET(pnode && pnode->pobjdata, CSBERR_PARAM);
	switch (pnode->pobjdata->type) {
	case EMITTER:
		list_clear(&pnode->bulist, (node_data_handle)emitterbu_buf_return);
		break;
	case LASER:
		list_clear(&pnode->bulist, (node_data_handle)laserbu_buf_return);
		break;
	default:
		list_clear(&pnode->bulist, NULL);
		break;
	}
}

CSB_DLL void csnode_buf_return(csnode_t* pnode)
{
	csnode_zero_bulist(pnode);
	if ((CSBERR_NOERR == csberrno) && pnode->pobj)
		csobj_buf_return(pnode->pobj, pnode->pobjdata->type);
	CS_BUF_RETURN(csnode_t, pnode);
}

CSB_DLL void csnode_update(csnode_t* pcsnode)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_VRET(pcsnode, CSBERR_PARAM);
	// 计算发射器的帧
	++pcsnode->nframe;
	if (pcsnode->nframe < pcsnode->pobjdata->fs ) {
		if (!pcsnode->bulist.size)
			return;
	} else if(pcsnode->nframe > pcsnode->pobjdata->fe) {
		if ((pcsnode->pobjdata->fe + 1) == pcsnode->nframe && pcsnode->cbs.on_end) {
			pcsnode->cbs.on_end(pcsnode, pcsnode->cbs.udata);
		}
		if (pcsnode->nframe > pcsnode->pobjdata->totalframe) {
			pcsnode->nframe = 0;
			pcsnode->pobj->life = 0;
			next_emit_time(pcsnode);
		}
	} else {
		// life begin call back
		if (pcsnode->pobjdata->fs + 1 == pcsnode->nframe && pcsnode->cbs.on_begin) {
			pcsnode->cbs.on_begin(pcsnode, pcsnode->cbs.udata);
		}
		// 计算发射周期执行发射得到新的元素
		if (pcsnode->nextEm <= pcsnode->nframe) {
			if (!CSB_FLAG_TEST(pcsnode->ctlflag, NODE_CTL_STOP_EMIT)) {
				csnode_emit_bullet(pcsnode);
			}
			next_emit_time(pcsnode);
		}
	}
	csnode_update_obj(pcsnode);
#ifdef CSNODE_ENALBE_ONFRAME_CALL
	if (pcsnode->cbs.on_frame) {
		pcsnode->cbs.on_frame(pcsnode, pcsnode->cbs.udata);
	}
#endif
}

CSB_DLL void csnode_emit_bullet(csnode_t* pcsn)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_VRET(pcsn, CSBERR_PARAM);
	switch (pcsn->pobjdata->type) {
	case EMITTER:
		emitter_emit(pcsn);
		return;
	case LASER:
		laser_emit(pcsn);
		return;
	default:
		csberrno = CSBERR_PARAM;
		return;
	}
}


CSB_DLL void csnode_update_obj(csnode_t* pcsn)
{
	csberrno = CSBERR_NOERR;
	CSB_NO_ERR_VRET(pcsn, CSBERR_PARAM);
	bool updateObj = !CSB_FLAG_TEST(pcsn->ctlflag, NODE_CTL_STOP_OBJ);
	bool updateBullet = !CSB_FLAG_TEST(pcsn->ctlflag, NODE_CTL_STOP_BULLET);
	if (pcsn->cbs.on_am)
		pcsn->cbs.on_am(&pcsn->cbs.autoPos, pcsn->cbs.udata);
	++pcsn->pobj->life;
	switch (pcsn->pobjdata->type) {
	case EMITTER:
		emitter_update(pcsn, updateObj, updateBullet);
		break;
	case LASER:
		laser_update(pcsn, updateObj, updateBullet);
		break;
	default:
		csberrno = CSBERR_PARAM;
		return;
	}
}

#ifdef __cplusplus
} // end of extern C
#endif
